#include "EventLoop.hpp"

namespace xww
{
    EventLoop::EventLoop(Acceptor &acceptor)
    :_epfd(createEpollFd())// 创建epoll文件描述符
    ,_isLooping(false)// 是否在循环中
    ,_acceptor(acceptor)
    ,_evtArr(1000) // 初始化事件数组，大小为1000
    ,_conns()
    {
        // 将Acceptor的监听套接字添加到epoll事件中
        addEpollReadEvent(_acceptor.getListenFd());
    }

    EventLoop::~EventLoop()
    {
        close(_epfd); // 关闭epoll文件描述符
    }

    void EventLoop::loop()
    {
        _isLooping = true;
        while(_isLooping)
        {
            waitEpollFd(); // 等待epoll事件
        }
    }

    void EventLoop::unloop()
    {
        _isLooping = false; // 设置循环标志为false，退出循环
    }

    int EventLoop::createEpollFd()
    {
        int fd = epoll_create1(0);
        if(fd < 0)
        {
            perror("epoll_create1");
        }
        return fd;
    }

    void EventLoop::addEpollReadEvent(int fd)
    {
        struct epoll_event ev;
        memset(&ev,0,sizeof(ev));
        ev.data.fd = fd;
        ev.events = EPOLLIN; // 关注读事件
        int ret = epoll_ctl(_epfd,EPOLL_CTL_ADD,fd,&ev);
    }

    void EventLoop::delEpollReadEvent(int fd)
    {
        struct epoll_event ev;
        memset(&ev,0,sizeof(ev));
        ev.data.fd = fd;
        ev.events = EPOLLIN; // 关注读事件
        int ret = epoll_ctl(_epfd,EPOLL_CTL_DEL,fd,&ev);
    }

    void EventLoop::waitEpollFd()
    {
        //epoll_wait的函数是干什么的？有什么作用？
        //epoll_wait函数用于等待I/O事件的发生
        //它会阻塞当前线程，直到有事件发生或者超时
        //函数原型：int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
        //参数说明：
        //epfd: epoll文件描述符
        //events: 用于存储发生的事件的数组
        //maxevents: events数组的大小
        //timeout: 超时时间，单位为毫秒，-1表示无限等待，
        int ret = epoll_wait(_epfd, _evtArr.data(), _evtArr.size(), 5000);
        if (ret == -1 && errno == EINTR)
        {
            return;  //为什么不能是continue？
                     //因为continue只能在循环中使用
                     //而这里是在if语句中
                     //所以应该使用return，直接返回
        }
        else if(ret == 0)
        {
            printf("Epoll timeout\n");
        }
        else
        {
            for(int i = 0; i < ret; ++i)
            {
                int fd = _evtArr[i].data.fd;// 获取事件发生的文件描述符
                // 判断是否是新连接
                // 为什么这样判断？
                // 因为Acceptor的监听套接字文件描述符是唯一的
                // 所以可以通过比较文件描述符来判断是否是新连接
                if(fd == _acceptor.getListenFd())
                {
                    handleNewConnection(); // 处理新连接
                }
                else
                {
                    handleMessage(fd); // 处理消息
                }
            }
        }
    }

    void EventLoop::handleNewConnection()
    {
        int netfd = _acceptor.accept(); // 接受新连接
        if(netfd < 0)
        {
            perror("accept error");
            return;
        }

        addEpollReadEvent(netfd); // 将新连接的文件描述符添加到epoll事件中

        //为什么要创建TcpConnection对象？
        //因为需要对新连接进行管理和处理
        TcpConnectionPtr conn(new TcpConnection(netfd));
        
        //为什么要设置三个回调函数？
        //因为需要在连接建立、消息到达和连接关闭时执行特定的操作
        conn->TsetAllCallback(_EonConnection, _EonMessage, _EonClose);

        //添加到容器map中
        // 这里使用std::make_pair创建一个键值对，键是netfd
        // 值是TcpConnectionPtr对象，然后插入到_conns映射中
        _conns.insert(std::make_pair(netfd, conn));

        // 调用连接回调函数
        conn->handleConnectionCallback();
    }

    void EventLoop::handleMessage(int fd)
    {
        auto it = _conns.find(fd);

        // 如果找到了对应的连接
        // 为什么要判断it != _conns.end()？
        // 因为如果没有找到对应的连接，it将指向_conns的end()
        // 这时不能对it->second调用成员函数
        // 否则会导致未定义行为
        // 所以需要先判断it是否有效
        // 如果it有效，说明找到了对应的连接
        if(it != _conns.end())
        {
            // 判断连接是否关闭
            bool isClosed = it->second->isClosed();
            if(isClosed)
            {
                // 连接已关闭，调用关闭回调函数
                it->second->handleCloseCallback();
                delEpollReadEvent(fd); // 从epoll中删除读事件
                _conns.erase(it); // 从_conns映射中删除连接
            }
            else
            {
                // 处理消息回调
                it->second->handleMessageCallback();
            }
        }
    }

}//end of namespace xww+